package com.itheima.demo2;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * 2025年9月17日15:36:46
 *      视频课的时间从2023.5.21.10.28跳到了2023.5.21.10.47
 *
 * 张全蛋儿  农家乐,野外拓展,轰趴
 * 李二狗子  轰趴,野外拓展,健身房
 * 翠花     野外拓展，轰趴
 * 小帅     健身房
 * 有容     农家乐
 * 1、请找出每个去处想去的人数是多少，并输出投票最多的去处是哪个。
 * 2、请找出哪些人没有选择投票最多的去处，输出他们的名字。
 */
public class Test2 {
    public static void main(String[] args) {
        // 1、发一：，用Map集合封装所有的人名和去处的数据     法二：磊哥说用面向对象的方法封装去解题也可以
        //用map集合的键来装人名，值选择用list集合的形式来装去处
        Map<String, List<String>> selects = new HashMap<>();
        List<String> data1 = new ArrayList<>();
        Collections.addAll(data1, "农家乐", "野外拓展", "轰趴");
        selects.put("张全蛋儿", data1);

        List<String> data2 = new ArrayList<>();
        Collections.addAll(data2, "轰趴", "野外拓展", "健身房");
        selects.put("李二狗子", data2);

        List<String> data3 = new ArrayList<>();
        Collections.addAll(data3,  "野外拓展", "轰趴");
        selects.put("翠花", data3);

        List<String> data4 = new ArrayList<>();
        Collections.addAll(data4, "健身房");
        selects.put("小帅", data4);

        List<String> data5 = new ArrayList<>();
        Collections.addAll(data5, "农家乐");
        selects.put("有容", data5);

        System.out.println(selects);

        // 2、找出每个去处选择的人数，输出人数最多的地方是哪里。定义一个infos的map集合来存储
        Map<String, Integer> infos = new HashMap<>();
        //遍历封装有全部去处和人名的map集合，得到map的value值集合
        selects.forEach((name, datas) -> {
            //再遍历值集合，然后把各个去处的人数添加到infos集合里面
            for (String data : datas) {
                //infos.get(data) infos集合根据去处的键，获取人数的值
                infos.put(data, infos.containsKey(data) ? infos.get(data) + 1 : 1);
            }
        });
        System.out.println("每个去处的人数是：");
        System.out.println(infos);

        // 3、输出去处最多的地方
/*       用stream流解题的潜在问题：stream流不会并存，假设去健身房和野外扩展的都是三个人，有可能会只输出健身房的三
        因为stream流很可能会去重，因为stream流的max只返回一个对象
        但是我有困惑：把map集合infos调用entrySet方法转换为set集合，然后调用max方法找最大值。这个map集合转换的set集合中
                    最大值是怎么排的？按照原map集合的值还是键排的呢？
        */

        System.out.println("输出去处最多的地方是:");
        Map.Entry<String, Integer> entry =
                infos.entrySet().stream().max((e1, e2) -> e1.getValue() - e2.getValue()).get();

        System.out.println("直接输出这个调用entrySet转换得到的entry，看看它是set还是map集合了:");
        System.out.println(entry);
        System.out.println("entry.getKey(): "+entry.getKey()+" entry.getValue():"+entry.getValue());

/*      上面entry找出了infos转换的set集合里面的最大值，然后再拿这个最大值去infos集合里面做比较，
        再次遍历infos转换为set集合的所有value值，然后过滤找出与最大值entry相等的所有值出来，
        然后把过滤出的所有最大值和entry的值相等的元素遍历，遍历输出相对应的键。
        */
/*        infos.entrySet().stream().filter(e->e.getValue() ==
                entry.getValue())
                .forEach(e-> System.out.println(e.getKey()));*/

/*      上面得到的结果需要保存起来，用于下面第四步使用。
        改进如下：
        把收集到的与最大值entry相等的元素不再遍历，而是收集到list集合中去，但是收集到的结果是Entry<String, Integer>类型
        所以要用List<Entry<String, Integer>>键值对来接收。但是我们只要人名，所以可以在收集之前在加工一下，
        e代表把前面filter过滤得到的去处最多的键值对，我们只要键。然后把获得的键加工为list

         *  <R>Stream<R>map(Function<? super T,? extends R>mapper)      对元素进行加工，并返回对应的新流
         * public static <T> Collector toList()        把元素收集到List集合中
        */
        List<String> names = infos.entrySet().stream().filter(e -> e.getValue() ==
                entry.getValue()).map(e -> e.getKey()).collect(Collectors.toList());
        System.out.println(names);


        // 4、哪些人没有选择去处最多的地方     所以要知道哪些去处是最多人选择的，那么上面第三步就需要保存起来，用于第四步的判断
        System.out.println("哪些人没有选择去处最多的地方：");
        selects.entrySet().stream().filter(e -> {
            // 信号位为true的，就是没有包含去处最多的
            boolean flag = true;
            //然后e拿到map集合selects的值的list集合，然后进行遍历
            for (String s : e.getValue()) {
                //第三步保存的去处最多的集合，用来与map集合selects遍历到的每个值，进行判断names是否包含便利的值。
                if(names.contains(s)) {
                    //如果包含，则说明这个键值对的人名不符合条件，结束循环，进入下一个stream流的循环（stream流的循环有时不太好理解）
                    flag = false;
                    break;
                }
            }
            //返回true的都是符合条件的，过滤出来后对符合条件的键值对输出键：
            return flag;
        }).forEach(e -> System.out.println(e.getKey()));

    }
}
